﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Common.Encrypt
{
    /// <summary>
    /// 提供MD5哈希算法
    /// <remarks>
    /// <para><![CDATA[哈希值大小为 128 位。MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式（将任意长度的字节串变换成一定长的十六进制数字串）。除了MD5以外，其中比较有名的还有sha-1、RIPEMD以及Haval等。 ]]> </para>
    /// <para><![CDATA[MD5算法具有以下特点：]]> </para>
    /// <para><![CDATA[     1、压缩性：任意长度的数据，算出的MD5值长度都是固定的。 ]]> </para>
    /// <para><![CDATA[     2、容易计算：从原数据计算出MD5值很容易。]]> </para>
    /// <para><![CDATA[     3、抗修改性：对原数据进行任何改动，哪怕只修改1个字节，所得到的MD5值都有很大区别。]]> </para>
    /// <para><![CDATA[     4、弱抗碰撞：已知原数据和其MD5值，想找到一个具有相同MD5值的数据（即伪造数据）是非常困难的。]]> </para>
    /// <para><![CDATA[     5、强抗碰撞：想找到两个不同的数据，使它们具有相同的MD5值，是非常困难的。]]> </para>
    /// </remarks>
    /// </summary>
    public static class MD5Provider
    {
        /// <summary>
        /// MD5签名
        /// </summary>
        /// <param name="str">需要签名的字符串</param>
        /// <param name="encoding">字符串编码</param>
        /// <example>
        /// <code>
        ///         private void EncodeDemo()
        ///        {
        ///             string str="这是字符串";
        ///             string md5=MD5Provider.Encode(str,Encoding.UTF8);
        ///        }
        /// </code>
        /// </example>
        /// <returns>返回一个str的MD5值</returns>
        public static string Encode(string str, Encoding encoding)
        {
            byte[] buffer = new MD5CryptoServiceProvider().ComputeHash(encoding.GetBytes(str));
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < buffer.Length; i++)
            {
                builder.AppendFormat("{0:x2}", buffer[i]);
            }
            return builder.ToString();
        }
        /// <summary>
        /// 计算MD5摘要
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static byte[] Encode(byte[] buffer)
        {
            var crypto = new MD5CryptoServiceProvider();
            return crypto.ComputeHash(buffer);
        }

        /// <summary>
        /// MD5签名，默认UTF-8编码
        /// </summary>
        /// <param name="str">需要签名的字符串</param>
        /// <example>
        /// <code>
        ///         private void EncodeDemo()
        ///        {
        ///             string str="这是字符串";
        ///             string md5=MD5Provider.Encode(str);
        ///        }
        /// </code>
        /// </example>
        /// <returns>返回一个str的MD5值</returns>
        public static string Encode(string str)
        {
            return Encode(str, Encoding.UTF8);
        }

        /// <summary>
        /// 文件MD5签名
        /// </summary>
        /// <param name="path">文件物理路径</param>
        /// <example>
        /// <code>
        ///         private void EncodeFileDemo()
        ///        {
        ///            //文件路径
        ///            string path = @"D:\File\text.txt";
        ///
        ///            //对文件MD5
        ///            string md5 = MD5Provider.EncodeFile(path);
        ///        }
        /// </code>
        /// </example>
        /// <returns>返回path指定的文件MD5值</returns>
        public static string EncodeFile(string path)
        {
            FileStream file = new FileStream(path, FileMode.Open);
            return EncodeFile(file);
        }

        /// <summary>
        /// 文件签名
        /// </summary>
        /// <param name="stream">文件流</param>
        /// <example>
        /// <code>
        ///         private void EncodeFileDemo()
        ///        {
        ///            //文件路径
        ///            string path = @"D:\File\text.txt";
        ///            //获取文件流
        ///            FileStream fileStream = new FileStream(path, FileMode.Open);
        ///            //对文件流MD5
        ///            string md5 = MD5Provider.EncodeFile(fileStream);
        ///        }
        /// </code>
        /// </example>
        /// <returns>返回path指定的文件MD5值</returns>
        /// <returns></returns>
        public static string EncodeFile(Stream stream)
        {
            System.Security.Cryptography.MD5 provider = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] retVal = provider.ComputeHash(stream);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
            {
                sb.Append(retVal[i].ToString("x2"));
            }
            return sb.ToString().ToUpper();
        }
    }
}
